package reversi;
// could be implemented as a base-class sub-class style instead of function based
//	will change upon decision of how the move validity checker occurs

import java.util.*;


public class AI_Base {
	
	private int difficulty;
	
	public AI_Base(){}	
	public AI_Base(int d){
		difficulty = d;
	}
	
	public int Get_Difficult(){return difficulty;}
	
	public int[] Choose_Move(Board board, char color, int difficulty){
		ArrayList<int[]> move_list = new ArrayList<int[]>();
		move_list = board.listLegalMoves(color);
		return Choose_Best_Move(board, move_list, color, difficulty);
	}
	
	
	
	int[] Choose_Best_Move(Board board, ArrayList<int[]> move_list, char color, int difficulty){
		switch(difficulty){
			case 0: //random moves
				return Choose_Best_Move_Random( board, move_list, color);
				
			case 1: //easy mode, search depth = 1
				//return Choose_Best_Move_Attack( board, move_list, color, 1);
				return Choose_Best_Move_Maximin( board, move_list, color, 1);
			case 2: //medium mode, search depth = 3
				//return Choose_Best_Move_Attack( board, move_list, color, 3);
				return Choose_Best_Move_Maximin( board, move_list, color, 3);
			case 3: // hard mode, search depth = 10
				//return Choose_Best_Move_Attack( board, move_list, color, 10);
				return Choose_Best_Move_Maximin( board, move_list, color, 5);
			default:
				System.out.println("Game Engine Error: AI System not Initialized");
				return new int[]{-1,-1}; // no legal AI difficulty
			}
	}
	
	int[] Choose_Best_Move_Random(Board board, ArrayList<int[]> move_list, char color){
		if(move_list.size()<1){
			return new int[]{-1,-1};		
		}
		return move_list.get((int)(Math.random()*move_list.size())); 
	}
	
	int[] Choose_Best_Move_Attack(Board board,ArrayList<int[]> move_list, char color, int depth){
		ArrayList<Integer> values = new ArrayList<Integer>();
		ArrayList<Board> boards = new ArrayList<Board>();
		
		if(depth>1){
			for(int i = 0; i < move_list.size(); i++){
				boards.add(board);
				boards.get(1).performMove(move_list.get(i)[0], move_list.get(i)[1],color);
				}
			
		}
		
		for(int i = 0; i < move_list.size(); i++){
			values.add(Valuate_Attack(board, boards.get(i), color, depth - 1));			
		}

		int max_val = -10000;
		int max_val_ind = 0;
		for(int i = 0; i < values.size(); i++){
			if(values.get(i) > max_val){
				max_val_ind = i;
				max_val = values.get(i);
			}
		}		
		
		return(move_list.get(max_val_ind));
		
	}
	
	int[] Choose_Best_Move_Defense(Board board,ArrayList<int[]> move_list, char color, int depth){
		ArrayList<Integer> values = new ArrayList<Integer>();
		ArrayList<Board> boards = new ArrayList<Board>();
		
		if(depth>1){
			for(int i = 0; i < move_list.size(); i++){
				boards.add(board);
				boards.get(1).performMove(move_list.get(i)[0], move_list.get(i)[1],color);
				}
			
		}
		
		for(int i = 0; i < move_list.size(); i++){
			values.add(Valuate_Defense(board, boards.get(i), color, depth - 1));			
		}

		int max_val = -10000;
		int max_val_ind = 0;
		for(int i = 0; i < values.size(); i++){
			if(values.get(i) > max_val){
				max_val_ind = i;
				max_val = values.get(i);
			}
		}		
		
		return(move_list.get(max_val_ind));
		
	}

	int Valuate_Attack(Board old_board, Board new_board, char color, int depth){
		int value = -99999;
		int opposing_move_count = new_board.listLegalMoves(Get_Other_Color(color)).size();
		int opposing_piece_dif = 0;
		if(color == 'W')
			opposing_piece_dif = old_board.countBlack() - new_board.countBlack();
		else
			opposing_piece_dif = old_board.countWhite() - new_board.countWhite();
		
		if(new_board.isGameOver()){
			if(new_board.whoWon() == color)
				value = 99999;		
		}
		
		else if(new_board.listLegalMoves(Get_Other_Color(color)).size()>0 && depth > 0){
			Board temp = new_board;
			int[] opposing_move = Choose_Best_Move_Defense(temp, temp.listLegalMoves(Get_Other_Color(color)), Get_Other_Color(color), depth - 1);
			temp.performMove(opposing_move[0], opposing_move[1], Get_Other_Color(color));
			Board temp2 = temp;
			int[] next_move = Choose_Best_Move_Attack(temp, temp.listLegalMoves(color), color, depth - 1);
			temp2.performMove(next_move[0], next_move[1], color);
			value = Valuate_Attack(temp, temp2, color, depth - 1);
		}
		else{
			//heuristic equation here!!!
			// currently: value = pieces captured + 50 - (3*number of opposing moves)
			value = (int)(opposing_piece_dif*(1) + 50 - opposing_move_count*(3)); 
			// the 50 is to make numbers positive for no real reason...
		}
		return value;
	}
	
	int Valuate_Defense(Board old_board, Board new_board, char color, int depth){
		int value = -99999;
		int move_count = new_board.listLegalMoves(color).size();
		int piece_dif = 0;
		if(color == 'B')
			piece_dif = old_board.countBlack() - new_board.countBlack();
		else
			piece_dif = old_board.countWhite() - new_board.countWhite();
		
		if(new_board.isGameOver()){
			if(new_board.whoWon() == color)
				value = 99999;		
		}
		
		else if(new_board.listLegalMoves(Get_Other_Color(color)).size()>0 && depth > 0){
			Board temp = new_board;
			int[] opposing_move = Choose_Best_Move_Attack(temp, temp.listLegalMoves(Get_Other_Color(color)), Get_Other_Color(color), depth - 1);
			temp.performMove(opposing_move[0], opposing_move[1], Get_Other_Color(color));
			Board temp2 = temp;
			int[] next_move = Choose_Best_Move_Defense(temp, temp.listLegalMoves(color), color, depth - 1);
			temp2.performMove(next_move[0], next_move[1], color);
			value = Valuate_Defense(temp, temp2, color, depth - 1);
		}
		else{
			//heuristic equation here!!!
			// currently: value = pieces +  (3*number of moves)
			value = (int)(piece_dif*(1) + move_count*(3)); 
		}
		return value;
				
	}
	
	
char Get_Other_Color( char color){
	if(color == 'W')
		return 'B';
	else if (color == 'B')
		return 'W';
	else{
		System.out.println("Internal Engine Error: AI color comparing");
		return color;
	}
}

int[] Choose_Best_Move_Maximin(Board board, ArrayList<int[]> move_list, char color, int depth){
	MaximinTree moves = new MaximinTree(board, true, depth, color);
	moves.Valuate(color);
	int max_val = -10000;
	int max_val_ind = 0;
	for(int i=0; i< moves.children.size(); i++){
		if(moves.children.get(i).value > max_val){
			max_val_ind = i;
			max_val = moves.children.get(i).value;
		}
	}
	if(move_list.size()==0){			return new int[]{-1,-1};		}
	return move_list.get(max_val_ind);

	
}



}


